//! Jaeger格式导出器
//! 
//! 将追踪数据导出为Jaeger兼容的格式

use crate::*;
use async_trait::async_trait;
use serde_json::json;
use std::time::UNIX_EPOCH;

/// Jaeger导出器
pub struct JaegerExporter {
    service_name: String,
}

impl JaegerExporter {
    /// 创建新的Jaeger导出器
    pub fn new(service_name: &str) -> Self {
        Self {
            service_name: service_name.to_string(),
        }
    }
}

#[async_trait]
impl TraceExporter for JaegerExporter {
    async fn export(&self, spans: &[TraceSpan]) -> TracingResult<String> {
        if spans.is_empty() {
            return Ok("{}".to_string());
        }

        // 按trace_id分组
        let mut traces_map = std::collections::HashMap::new();
        for span in spans {
            traces_map.entry(span.trace_id.clone())
                .or_insert_with(Vec::new)
                .push(span);
        }

        let mut traces = Vec::new();
        for (trace_id, trace_spans) in traces_map {
            let jaeger_spans: Vec<_> = trace_spans.iter().map(|span| {
                json!({
                    "traceID": trace_id,
                    "spanID": span.span_id,
                    "parentSpanID": span.parent_span_id,
                    "operationName": span.operation_name,
                    "startTime": span.start_time.duration_since(UNIX_EPOCH)
                        .unwrap_or_default().as_micros(),
                    "duration": span.finish_time
                        .and_then(|ft| ft.duration_since(span.start_time).ok())
                        .map(|d| d.as_micros())
                        .unwrap_or(0),
                    "flags": 1, // sampled
                    "tags": span.tags.iter().map(|(k, v)| json!({
                        "key": k,
                        "type": "string",
                        "value": v
                    })).collect::<Vec<_>>(),
                    "logs": span.logs.iter().map(|log| json!({
                        "timestamp": log.timestamp.duration_since(UNIX_EPOCH)
                            .unwrap_or_default().as_micros(),
                        "fields": log.fields.iter().map(|(k, v)| json!({
                            "key": k,
                            "value": v
                        })).collect::<Vec<_>>()
                    })).collect::<Vec<_>>(),
                    "process": {
                        "serviceName": self.service_name,
                        "tags": []
                    },
                    "references": []
                })
            }).collect();

            traces.push(json!({
                "traceID": trace_id,
                "spans": jaeger_spans
            }));
        }

        let result = json!({
            "data": traces
        });

        serde_json::to_string_pretty(&result)
            .map_err(|e| Box::new(TracingError::ExportError(e.to_string())) as Box<dyn std::error::Error + Send + Sync>)
    }

    fn name(&self) -> &str {
        "jaeger"
    }

    fn supported_format(&self) -> TraceExportFormat {
        TraceExportFormat::Jaeger
    }
}

#[cfg(feature = "jaeger")]
pub mod jaeger_client {
    use super::*;
    
    /// Jaeger客户端，用于向Jaeger Agent发送数据
    pub struct JaegerClient {
        endpoint: String,
        service_name: String,
        client: reqwest::Client,
    }

    impl JaegerClient {
        /// 创建新的Jaeger客户端
        pub fn new(endpoint: &str, service_name: &str) -> Self {
            Self {
                endpoint: endpoint.to_string(),
                service_name: service_name.to_string(),
                client: reqwest::Client::new(),
            }
        }

        /// 发送追踪数据到Jaeger
        pub async fn send_traces(&self, spans: &[TraceSpan]) -> TracingResult<()> {
            let exporter = JaegerExporter::new(&self.service_name);
            let data = exporter.export(spans).await?;

            let response = self.client
                .post(&format!("{}/api/traces", self.endpoint))
                .header("Content-Type", "application/json")
                .body(data)
                .send()
                .await
                .map_err(|e| Box::new(TracingError::NetworkError(e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;

            if !response.status().is_success() {
                return Err(Box::new(TracingError::NetworkError(
                    format!("Jaeger responded with status: {}", response.status())
                )));
            }

            Ok(())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashMap;

    #[tokio::test]
    async fn test_jaeger_exporter() {
        let exporter = JaegerExporter::new("test-service");
        
        let span = TraceSpan {
            trace_id: "test-trace-123".to_string(),
            span_id: "test-span-456".to_string(),
            parent_span_id: None,
            operation_name: "test-operation".to_string(),
            start_time: std::time::SystemTime::now(),
            finish_time: Some(std::time::SystemTime::now()),
            tags: {
                let mut tags = HashMap::new();
                tags.insert("http.method".to_string(), "GET".to_string());
                tags
            },
            logs: vec![],
        };

        let result = exporter.export(&[span]).await;
        assert!(result.is_ok());
        
        let exported = result.unwrap();
        assert!(exported.contains("test-trace-123"));
        assert!(exported.contains("test-span-456"));
        assert!(exported.contains("test-operation"));
    }
}